<?php


namespace App\Exception;


use App\Util\ResultUtil;
use Elite\Infrastructure\Helper\Logger;
use Elite\Infrastructure\Server\HttpCode;
use Elite\Infrastructure\Server\HttpException;
use Elite\Infrastructure\Exception\DumpDieException;
use Swoole\Http\Request;
use Swoole\Http\Response;
use Elite\Infrastructure\View\View;
use Throwable;

class HttpExceptionHandler {

    /**
     * @var Logger
     */
    private $logger;

    /**
     * @var Logger
     */
    private $serviceLogger;

    /**
     * @var Request
     */
    private $request;

    /**
     * @var Response
     */
    private $response;

    public function __construct(Request $request, Response $response) {
        $this->logger = logger('exception_' . date("Y-m-d") . '.log');
        $this->serviceLogger = logger('service_exception_' . date("Y-m-d") . '.log');
        $this->request = $request;
        $this->response = $response;
    }

    public function handle(Throwable $throwable) {
        if ($throwable instanceof DumpDieException) {
            $this->response->status(HttpCode::HTTP_STATUS_OK);
            $this->response->end($throwable->getMessage());
            return;
        }

        $this->writeExceptionLog($throwable);

        if ($throwable instanceof HttpException) {
            $this->response->status($throwable->getCode());
            return;
        }

        if ($throwable instanceof ServiceException) {
            $this->formatReturn($throwable, HttpCode::HTTP_STATUS_OK);
            return;
        }

        // 其他错误开发环境打印异常
        if ((config('env') === 'DEV')) {
            $this->response->end('<pre>' . $throwable . '</pre>');
        } else {
            $this->response->status(HttpCode::HTTP_STATUS_INTERNAL_SERVER_ERROR);
        }
    }

    private function formatReturn($throwable, $httpCode) {
        $error = ResultUtil::fail($throwable->getMessage(), $throwable->getCode());
        if (('XMLHttpRequest' === $this->request->header['x-requested-with']) || stripos($this->request->header['content-type'], 'application/json') !== false) {
            $this->response->header('Content-Type', 'application/json');
            $this->response->status($httpCode);
            $this->response->end(json_encode($error));
        } else {
            $errorPage = new View('error', $error);
            $this->response->end($errorPage->getContent());
        }
    }

    private function writeExceptionLog(Throwable $throwable) {
        $errorList[] = "{$throwable->getMessage()} In {$throwable->getFile()} Line {$throwable->getLine()}";
        $errorList[] = "Call Stack:";
        $errorList[] = $throwable->getTraceAsString();
        $stack = implode("\r\n", $errorList);
        if ((config('env') === 'DEV')) {
            var_dump($stack);
        }
        if ($throwable instanceof ServiceException) {
            $this->serviceLogger->error($stack);
            return;
        }
        $this->logger->error($stack);
    }

}